package com.stanwind.netty.api;

import com.stanwind.netty.constant.*;
import com.stanwind.netty.core.protocol.model.Response;
import com.stanwind.netty.domain.pojo.Card;
import com.stanwind.netty.domain.pojo.Player;
import com.stanwind.netty.domain.pojo.Room;
import com.stanwind.netty.serialize.*;
import com.stanwind.netty.service.CharacterService;
import com.stanwind.netty.task.DeclareSecTask;
import com.stanwind.netty.task.DeclareTask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.*;

/**
 * Created by StanWind on 2017/2/17.
 */
@Component
public class RoomUtils {
    @Autowired
    private Log log;

    private List<Room> rooms;

    public List<Room> getRooms() {
        return rooms;
    }

    public void setRooms(List<Room> rooms) {
        this.rooms = rooms;
    }

    /**
     * 初始化房间
     */
    @PostConstruct
    public void init() {
        rooms = new ArrayList<Room>();
    }


    /**
     * 匹配房间
     *
     * @param player 玩家对象
     * @return
     */
    public Room matchRoom(Player player) {
        Room desRoom = null;

        //TODO 没发退出房间 或者重复进入
        if (player.getRoomId() > 0) {
            return getRoomByRoomId(player.getRoomId());
        }


        if (desRoom == null) {
            //遍历所有房间 找可用房
            for (Room room : getRooms()) {
                if (roomIsUse(room))
                    desRoom = room;
            }

        }

        //没有房间就新开房间
        if (desRoom == null)
            desRoom = getRoomByRoomId(openRoom());

        //设置玩家房间号
        player.setRoomId(desRoom.getRoomID());
        //设置玩家座位号
        player.setSeatId(getSeatId(desRoom, player));

        //TODO 发送该玩家进入
        Response response = new Response();
        AddPlayer addPlayer = new AddPlayer();
        addPlayer.setPlayer(player);
        response.setData(addPlayer.getBytes());
        response.setCmd(Command.CMD_ADDPLAYER);
        boardResponse(desRoom, response);

        //房间增加玩家
        desRoom.getPlayers().add(player);

        log.getLogger().debug("Player " + player.getCharacter().getNickname() + " In->RoomId " + player.getRoomId() + "SeatId->" + player.getSeatId());

        return desRoom;
    }


    /**
     * 根据roomId获取room
     *
     * @param roomId
     * @return
     */
    public Room getRoomByRoomId(int roomId) {
        return roomId > 0 ? getRooms().get(roomId - 1) : null;
    }


    /**
     * 退出房间
     *
     * @param player 玩家对象
     * @return 成功退出返回true 房间正在游戏返回false
     */
    public boolean exitRoom(Player player) {
        //先判断是否在游戏
        Room room = getRoomByRoomId(player.getRoomId());
        if (room == null)
            return false;

        if (room.isGame()) {
            player.setChannel(null);
            player.setOffline(true);
            return false;
        } else {
            //删除房间缓存
            room.getPlayers().remove(player);
            //群发玩家退出消息
            boardExitRoom(player.getCharacter().getAccountId(), room);
            return true;
        }
    }

    /**
     * 发送退出
     *
     * @param accountId
     * @param room
     */
    public void boardExitRoom(String accountId, Room room) {
        DelPlayer delPlayer = new DelPlayer();
        delPlayer.setAccountId(accountId);
        Response response = new Response();
        response.setCmd(Command.CMD_EXITROOM);
        response.setData(delPlayer.getBytes());
        boardResponse(room, response);

    }


    /**
     * 群发消息到房间
     *
     * @param roomId   房间号
     * @param response 消息对象
     */
    public void boardResponse(int roomId, Response response) {
        boardResponse(getRoomByRoomId(roomId), response);
    }


    /**
     * 群发消息到房间
     *
     * @param room
     * @param response
     */
    public void boardResponse(Room room, Response response) {
        synchronized (this) {
            if (room == null)
                return;
            List<Player> players = room.getPlayers();
            for (Player player : players) {
                if (player.getChannel() != null)
                    player.getChannel().write(response);
            }
        }
    }


    /**
     * 获取空的seatId
     *
     * @param room 房间对象
     * @return seatId
     */
    private int getSeatId(Room room, Player player) {
        if (player.getSeatId() > 0)
            return player.getSeatId();

        int id = -1;
        int[] s = {1, 2, 3};

        List<Player> players = room.getPlayers();
        for (Player p : players) {
            id++;
            s[p.getSeatId() - 1] = -1;
            //{-1,-1,3}
        }
        id = -1;
        for (int i = 0; i < 3; i++) {
            if (s[i] != -1)
                return s[i];
        }
        return id;
    }


    /**
     * 新开房间
     */
    private int openRoom() {
        Room room = new Room();
        int id;
        synchronized (this) {
            rooms.add(room);
            id = rooms.size();
            room.setRoomID(id);
        }
        return id;
    }

    /**
     * 房间是否可以进入
     *
     * @return 可以返回真
     */
    private boolean roomIsUse(int roomId) {
        return roomIsUse(getRoomByRoomId(roomId));
    }

    private boolean roomIsUse(Room room) {
        List<Player> players = room.getPlayers();
        return players.size() < ServerSetting.ROOM_SIZE;
    }

    /**
     * 进入房间
     *
     * @param roomId 房间号
     * @param player 玩家
     * @return 是否进入成功
     */
    private boolean getInRoom(int roomId, Player player) {
        Room room = getRoomByRoomId(roomId);
        return this.getInRoom(room, player);
    }

    /**
     * 进入房间
     *
     * @param room   房间对象
     * @param player 玩家对象
     * @return 是否进入成功
     */
    private boolean getInRoom(Room room, Player player) {
        if (room == null || room.getPlayers().size() > ServerSetting.ROOM_SIZE)
            return false;
        synchronized (this) {
            List<Player> players = room.getPlayers();
            players.add(player);
        }
        return true;
    }


    /**
     * 检查房间是否可以开始游戏
     *
     * @param roomId 房间号
     * @return
     */
    public boolean checkStart(int roomId) {
        Room room = getRoomByRoomId(roomId);
        if (room == null)
            return false;

        //检查人数是否达到3人
        if (room.getPlayers().size() < ServerSetting.ROOM_SIZE)
            return false;

        boolean start = true;
        for (Player player : room.getPlayers()) {
            //准备且不是离线
            if (!player.isReady() || player.isOffline())
                start = false;
        }
        return start;
    }

    @Autowired
    private NumberUtils numberUtils;

    /**
     * 初始化房间扑克牌
     *
     * @param room
     */
    public void initRoomCards(Room room) {
        List<Card> cards = new ArrayList<>();
        //扑克牌初始化
        for (int i = 1; i <= 13; i++) {
            for (int j = 1; j <= 4; j++) {
                Card card = new Card();
                card.setWeight((CardWeight) numberUtils.enumParse(CardWeight.class, i));
                card.setSuit((CardSuit) numberUtils.enumParse(CardSuit.class, j));
                cards.add(card);
            }
        }
        //  小王
        Card queen = new Card();
        queen.setSuit(CardSuit.Blank);
        queen.setWeight(CardWeight.Queen);
        //  大王
        Card king = new Card();
        king.setSuit(CardSuit.Blank);
        king.setWeight(CardWeight.King);
        cards.add(queen);
        cards.add(king);
        room.setCards(cards);
    }

    @Autowired
    private ApplicationContext context;

    /**
     * 开始游戏
     *
     * @param roomId
     */
    public void startGame(int roomId) {
        Room room = getRoomByRoomId(roomId);
        if (room == null)
            return;
        log.getLogger().info("Room->" + roomId + "  开始发牌");
        //开始游戏标识
        room.setGame(true);
        //初始化房间牌
        initRoomCards(room);
        //给三人发牌 第一波
        List<Player> players = room.getPlayers();
        for (Player player : players) {
            //随机发牌
            List<Card> cards = new ArrayList<>();
            for (int i = 0; i < 17; i++) {
                cards.add(room.getRandCard());
            }
            Collections.sort(cards);            // 排序
            player.setHandCards(cards);
            log.getLogger().info("Player->" + player.getCharacter().getNickname() + "  Cards->" + cards);
            //发送消息
            Response response = new Response();
            DispatchCards dispatchCards = new DispatchCards();
            dispatchCards.setCards(player.getHandCards());
            response.setCmd(Command.CMD_DISPATCH);
            response.setData(dispatchCards.getBytes());
            player.getChannel().write(response);
        }

        //指定叫地主的玩家
        Random random = new Random();
        //随机出先手玩家
        Player declarer = players.get(random.nextInt(players.size()));
        //先把庄家放在地主位置 走完一轮先
        room.setLandlord(declarer);
        //房间数据初始化
        room.initGame(declarer);

        //告知庄家可以开始叫地主
        sendStep(room, declarer.getCharacter().getAccountId(), ServerSetting.DECLARE_TIME);

        //启动超时检测任务
        Timer timer = new Timer();
        room.setTimer(timer);       //  可控

        timer.schedule(context.getBean(DeclareTask.class, room), ServerSetting.DECLARE_TIME);

        log.getLogger().info("Room->" + roomId + " 玩家:" + declarer.getCharacter().getNickname() + " 开始叫地主");
    }


    /**
     * 如果accountId不为空 发送地主三张牌 发送地主
     *
     * @param room
     * @param accountId
     */

    public void sendLandlord(Room room, String accountId) {
        //推送庄家
        Response response = new Response();
        Landlord landlord = new Landlord();
        landlord.setAccountId(accountId);
        response.setCmd(Command.CMD_PUB_LANDLORD);
        response.setData(landlord.getBytes());
        boardResponse(room, response);

        //推送庄家牌
        log.getLogger().info("玩家 " + room.getLandlord().getCharacter().getNickname() + " 成为地主->" + room.getCards());
        LandlordCard landlordCard = new LandlordCard();
        landlordCard.setRoom(room);
        response.setData(landlordCard.getBytes());
        response.setCmd(Command.CMD_LANDLORD_CARD);
        boardResponse(room, response);
        room.getLandlord().getHandCards().addAll(room.getCards());

    }


    /**
     * 群发当前步骤信息
     *
     * @param room          房间对象
     * @param accountId     当前操作人id
     * @param operatingTime 操作时间
     */
    public void sendStep(Room room, String accountId, int operatingTime) {
        log.getLogger().error("Step->" + room.getGameStep());
        Response response = new Response();
        StepCall stepCall = new StepCall();
        stepCall.setAccountId(accountId);
        stepCall.setGameStep(room.getGameStep());
        stepCall.setOperatingTime(operatingTime);
        response.setCmd(Command.CMD_STEPCALL);
        response.setData(stepCall.getBytes());
        boardResponse(room, response);
    }


    /**
     * 开始游戏叫地主
     *
     * @param room 坊间对象
     */
    public void startDeclareSec(Room room) {
        Timer timer = room.getTimer();
        if (timer != null)
            timer.cancel();

        if (room.getGameStep().getValue() == GameStep.DECLARE_LANDLORD.getValue()) {
            //开始第二轮
            room.setGameStep(GameStep.DECLARE_LANDLORD_SEC);
            room.setCurrentPlayer(room.getLandlordList().get(0));
            timer = new Timer();
            timer.schedule(context.getBean(DeclareSecTask.class, room), ServerSetting.DECLARE_TIME);
        }
    }

    /**
     * 选定地主 开始
     *
     * @param room 房间对象
     */
    public void startPayCards(Room room) {
        Timer timer = room.getTimer();
        if (timer != null)
            timer.cancel();
        timer = new Timer();
        room.setTimer(timer);

//        if(room.getGameStep().getValue()==GameStep.DECLARE_LANDLORD_SEC.getValue()){
        //开始出牌
        room.setGameStep(GameStep.PAY_CARD);
        room.setCurrentPlayer(room.getLandlord());
        timer.schedule(context.getBean(DeclareSecTask.class, room), ServerSetting.EAT_CARD_TIME);
        log.getLogger().info("开始出牌->" + room.getLandlord().getCharacter().getNickname());
        sendStep(room, room.getLandlord().getCharacter().getAccountId(), ServerSetting.EAT_CARD_TIME);
//        }
    }

    /**
     * 发送所有玩家手牌显示
     *
     * @param room
     */
    public void sendAllPlayerCards(Room room) {
        ShowCards showCards = new ShowCards();
        showCards.setPlayers(room.getPlayers());
        Response response = new Response();
        response.setData(showCards.getBytes());
        response.setCmd(Command.CMD_SHOWCARDS);
        boardResponse(room, response);
    }

    /**
     * 发送给玩家更改的金币
     *
     * @param room
     */
    public void sendAllPlayerChangeGolds(Room room) {
        UpdateGolds updateGolds = new UpdateGolds();
        updateGolds.setPlayers(room.getPlayers());
        Response response = new Response();
        response.setData(updateGolds.getBytes());
        response.setCmd(Command.CMD_UPDATEMONEY);
        boardResponse(room, response);
    }

    @Autowired
    private CharacterService characterService;

    /**
     * 保存变更的金币
     * @param room 房间对象
     */
    public void saveAllPlayerChangeGolds(Room room) {
        List<Player> players = room.getPlayers();
        for (Player player : players) {
            player.getCharacter().setGold(player.getCharacter().getGold() + player.getChangedGolds());
            player.setChangedGolds(0);
            System.err.println(player.getCharacter().getNickname() + "->" + player.getCharacter().getGold());
            characterService.updateByAccountId(player.getCharacter());
        }
    }

}
